Homographic usage examples:
%%html
<iframe src="http://www.in2white.com/" width="700" height="600"></iframe>

Given a set of matches, what parametric model describes a geometrically consistent transformation?


plot_images(img,Titles,(1,4),figsize=(16,4),fontsize=20)
plt.figure(figsize=(12,4))
plt.subplot(131)
plt.imshow(im),plt.title('Perspective input',fontsize=20)
plt.plot(pts1[:,0],pts1[:,1],'m*')
plt.axis('off')
plt.subplot(132),plt.imshow(im_perspective),plt.title('Perspective',fontsize=20)
plt.plot(pts2[:,0],pts2[:,1],'m*')
plt.axis('off')
plt.subplot(133),plt.imshow(img_cyl)
plt.title('Cylindrical',fontsize=20)
_ = plt.axis('off')

# Translation:
tx,ty = [10,20]
h_T = np.float32([[1,0,tx],[0,1,ty],[0,0,1]])
im_T = cv2.warpPerspective(im, h_T,(cols,rows))
plot_images([img[0],img[1]],[Titles[0],Titles[1]],(1,2),figsize=(12,12),fontsize=20)
# Rotation:
theta = np.deg2rad(20)
h_R = np.float32([[np.cos(theta),-np.sin(theta),0],[np.sin(theta),np.cos(theta),0],[0,0,1]])
im_R = cv2.warpPerspective(im, h_R,(cols,rows))
plot_images([img[0],img[2]],[Titles[0],Titles[2]],(1,2),figsize=(12,12),fontsize=20)
H = h_T @ h_R
im_temp = cv2.warpPerspective(im, H, (cols, rows))
plot_images([img[0], im_temp], [Titles[0], 'Rigid'], (1,2), figsize=(12,12), fontsize=20)
# scaling
s = 1.5
h_s = np.array([[s, 0, 0], [0, s, 0], [0, 0, 1]],np.float32)
im_s = cv2.warpPerspective(im, h_s, (cols, rows))
plot_images([img[0], im_s],[Titles[0],'Scale'], (1, 2), figsize=(12,12), fontsize=20)
Similarity transform (4 DoF) = translation + rotation + scale
h_sim = h_s @ h_T @ h_R
im_sim = cv2.warpPerspective(im, h_sim, (cols, rows))
plot_images([img[0], im_sim], [Titles[0], 'Similarity'], (1,2), figsize=(12,12), fontsize=20)
# Aspect Ratio
a = 1 / 2
h_ar = np.array([[a, 0, 0], [0, 1 / a, 0], [0, 0, 1]], np.float32)
im_ar = cv2.warpPerspective(im, h_ar, (cols,rows))
plot_images([img[0], im_ar], [Titles[0], 'Aspect Ratio'], (1,2), figsize=(12,12), fontsize=20)
# shear
a,b = (0.5, 0.1)
h_sh = np.array([[1, a, 0],[b, 1, 0], [0, 0, 1]], np.float32)
im_sh = cv2.warpPerspective(im, h_sh, (cols, rows))
plot_images([img[0], im_sh], [Titles[0], 'Shear'], (1,2), figsize=(12,12), fontsize=20)
Affine transform (6 DoF) = translation + rotation + scale + aspect ratio +shear
# affine transform
h_aff = h_ar @ h_sh @ h_s @ h_T @ h_R
im_aff = cv2.warpPerspective(im, h_aff, (cols * 4, rows * 4))
plot_images([img[0], im_aff], [Titles[0], 'Affine'], (1,2), figsize=(12,12), fontsize=20)
Non-linear!
# Perspective
pts1 = np.float32([[100,77],[320,105],[100,150],[385,170]])
pts2 = np.float32([[0,0],[300,0],[0,100],[300,50]])
h_per = cv2.getPerspectiveTransform(pts1,pts2)
im_perspective = cv2.warpPerspective(im,h_per,(400,300))
plot_images([img[0], im_perspective], [Titles[0], 'Projective'], (1, 2), figsize=(12,12), fontsize=20)
Homography maps between:
For far away objects:
A_inv = pinv(A)
h = np.linalg.pinv(A)@b
where A is full rank. We are obviously not interested in the trivial solution $h=0$ hence we add the constraint $$||h||=1$$
Compute Projective transformation using SVD: $$arg \min_h{||Ah||_2^2} \text{, } s.t ||h||_2^2=1 $$
Hence, we get the following minimization problem:
$$ arg \min_h||DV^Th|| \text{ s.t. } ||V^Th||=1 $$In Python:
(U,D,Vh) = np.linalg.svd(A,False)
h = Vh.T[:,-1]
Lagrange multipliers - Least–squares Solution of Homogeneous Equations
Using EVD (eigenvalue decomposition) on $A^TA$.
The RANSAC algorithm is extremly simple, but it often
Many improved algorithms:
cv2.findHomography(src_pts, dst_pts, cv2.RANSAC)


Obtain a wider angle view by combining multiple images



What if pixel lands “between” two pixels?
Answer: add “contribution” to several pixels and normalize (splatting)
For each pixel x’ in image 2 find its origin x in image 1
Problem: What if pixel comes from “between” two pixels?
Sampling at $f(x,y)$:
Python:
interp2d() - https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp2d.htmlcv2.warpPerspective(im,*,*,cv2.WARP_INVERSE_MAP)
cols/2)plot_images([A_,B_],['Apple','Orange'],(1,2),figsize=(12,12),fontsize=20)
plot_images([real,ls_],['Original','Pyramid Blend'],(1,2),figsize=(12,12),fontsize=20)
plot_images([real,MASK,ls_],['Original','Mask','Alpha Blending'],(1,3),figsize=(18,12),fontsize=20)
plot_images([real,ls_],['Original','Texture'],(1,2),figsize=(12,12),fontsize=20)
kornia.geometry - https://kornia.readthedocs.io/en/latest/geometry.html